package net.sf.nlp.ltag.data;

import java.util.ArrayList;
import java.util.List;


public class LTAGNode implements Cloneable
{
	private String type;
	private String nodeText;
	private String semanticTag;
	private int location = -1;
	private Word word;
	private int leafIndex = -1;
	private LTAGNode parent;
	private List<LTAGNode> children;
	private boolean intermediateNode = false;
	private int level = -1;
	private int minLevel = Integer.MAX_VALUE;
	
	private List<LTAGNode> leafNodes;
	public enum StringType {Full, LTAG, LTAG_NO_WORD, SuperLTAG};
	
	public String getType() {
		return type;
	}
	public void setType(String type) {
		this.type = type;
	}
	public String getSemanticTag() {
		return semanticTag;
	}
	public void setSemanticTag(String semanticTag) {
		this.semanticTag = semanticTag;
	}
	public int getLocation() {
		return location;
	}
	public void setLocation(int location) {
		this.location = location;
	}
	public Word getWord() {
		return word;
	}
	public void setWord(Word word) {
		this.word = word;
	}
	public int getLeafIndex() {
		return leafIndex;
	}
	public void setLeafIndex(int leafIndex) {
		this.leafIndex = leafIndex;
	}
	public LTAGNode getParent() {
		return parent;
	}
	public void setParent(LTAGNode parent) {
		this.parent = parent;
	}
	public List<LTAGNode> getChildren() {
		return children;
	}
	public void setChildren(List<LTAGNode> children) {
		this.children = children;
	}
	public String getNodeText() {
		return nodeText;
	}
	public void setNodeText(String nodeText) {
		this.nodeText = nodeText;
	}
	public boolean isIntermediateNode() {
		return intermediateNode;
	}
	public void setIntermediateNode(boolean intermediateNode) {
		this.intermediateNode = intermediateNode;
	}
	public LTAGNode getRightBrother()
	{
		int index = parent.getChildren().indexOf(this);
		
		if (index == -1)
			System.out.println(new Exception("The tree is not correct"));
		
		if (index + 1 < parent.getChildren().size())
			return parent.getChildren().get(index + 1);
		
		return null;
	}
	public LTAGNode getLeftBrother()
	{
		int index = parent.getChildren().indexOf(this);
		
		if (index == -1)
			System.out.println(new Exception("The tree is not correct"));
		
		if (index - 1 >= 0)
			return parent.getChildren().get(index - 1);
		
		return null;
	}
	
	public boolean isChildOfNode(LTAGNode node)
	{
		LTAGNode parent = this;
		
		while (parent != null)
		{
			if (parent == node)
				return true;
			
			parent = parent.getParent();
		}
		
		return false;
	}
	
	public int getLevel()
	{
		if (level == -1)
			getLevel(this, 1);
		
		return level;
	}
	
	private void getLevel(LTAGNode node, int tempLevel)
	{
		if (level < tempLevel)
			level = tempLevel;
		
		List<LTAGNode> children = node.getChildren();
		if (children != null && children.size() > 0)
		{
			for (LTAGNode child : children)
				getLevel(child, tempLevel + 1);
		}
	
	}
	
	public int getMinLevel() 
	{
		if (minLevel == Integer.MAX_VALUE)
			getMinLevel(this, 1);
		
		return minLevel;
	}
	
	private void getMinLevel(LTAGNode node, int tempLevel)
	{
		List<LTAGNode> children = node.getChildren();
		if (children != null && children.size() > 0)
		{
			for (LTAGNode child : children)
				getMinLevel(child, tempLevel + 1);
		}
		else
		{
			if (minLevel > tempLevel)
				minLevel = tempLevel;
		}
		
	}
	
	public String getPath()
	{
		StringBuffer path = new StringBuffer(nodeText);
		
		LTAGNode node = this;
		LTAGNode parent = null;
		while ((parent = node.getParent()) != null)
		{
			path.insert(0, parent.getNodeText() + "-");
			
			node = parent;
		}
		
		return path.toString();
	}
	
	public List<LTAGNode> getLeafNodes()
	{
		if (leafNodes != null)
			return leafNodes;
		
		leafNodes = new ArrayList<LTAGNode>();
		
		getLeafNodes(this);
		
		return leafNodes;
	}
	
	private void getLeafNodes(LTAGNode node)
	{
		List<LTAGNode> children = node.getChildren();
		
		if (children == null || children.size() == 0)
		{
			leafNodes.add(node);
		}
		else
		{
			for (LTAGNode child : children)
				getLeafNodes(child);
		}
	}
	
	
	public String toString()
	{
		StringBuffer sb = new StringBuffer(toSimpleString());
		
		if (children != null && children.size() > 0)
		{
			if (children.size() > 1)
				sb.append(" (");
			
			for (LTAGNode child : children)
			{
				sb.append(child.toString());
				sb.append(" ");
			}
			
			sb.deleteCharAt(sb.length() - 1);
			
			if (children.size() > 1)
				sb.append(")");
		}
		
		if (this.getParent() != null)
		{
			sb.insert(0, "(");
			sb.append(")");
		}
		return sb.toString();
	}
	
	public String toString(StringType stringType)
	{
		StringBuffer sb = new StringBuffer(toSimpleString(stringType));
		
		if (children != null && children.size() > 0)
		{
			sb.append(" (");
			
			for (LTAGNode child : children)
			{
				sb.append(child.toString(stringType));
				sb.append(" ");
			}
			
			sb.deleteCharAt(sb.length() - 1);
			sb.append(")");
		}
		
		return sb.toString();
	}
	
	public String toSimpleString()
	{
		return toSimpleString(StringType.Full);
	}
	
	public String toSimpleString(StringType stringType)
	{
		StringBuffer sb = new StringBuffer(nodeText);
		
		if (stringType != StringType.SuperLTAG && semanticTag != null)
			sb.append("-").append(semanticTag);
		
		if (type != null)
			sb.append(type);
		
		if (stringType != StringType.SuperLTAG && stringType!= StringType.LTAG_NO_WORD && word!= null)
			sb.append(" ").append(word.getLexical());
		
		if (stringType == StringType.Full && intermediateNode)
			sb.append("+");
		
		return sb.toString();
	}
	
	public String toLTAG()
	{
		return toString(StringType.LTAG);
	}
	
	public String toLTAGNoWord()
	{
		return toString(StringType.LTAG_NO_WORD);
	}
	
	public String toSuperLTAG()
	{
		return toString(StringType.SuperLTAG);
	}
	
	public LTAGNode clone()
	{
		LTAGNode clone = null;
		
		try 
		{
			clone = (LTAGNode)super.clone();
			
			if (children != null)
			{
				List<LTAGNode> cloneChildren = new ArrayList<LTAGNode>();
				
				for (LTAGNode child : children)
				{
					LTAGNode cloneChild = child.clone();
					
					cloneChild.setParent(clone);
					cloneChildren.add(cloneChild);
				}
				
				clone.setChildren(cloneChildren);
			}
		} 
		catch (CloneNotSupportedException e) 
		{
			e.printStackTrace();
		}
		
		return clone;
	}
}
